/*
 *  Copyright 2019-2023 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package me.zhengjie.modules.biz.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import me.zhengjie.exception.BizException;
import me.zhengjie.modules.biz.domain.EnrollSingle;
import me.zhengjie.modules.biz.domain.Vip;
import me.zhengjie.modules.biz.domain.dto.RecommendUniversitiesDTO;
import me.zhengjie.modules.biz.domain.resp.UniversitiesRecommendResp;
import me.zhengjie.modules.biz.domain.req.UniversitiesRecommendReq;
import me.zhengjie.modules.biz.mapper.VipMapper;
import me.zhengjie.modules.system.domain.WxUser;
import me.zhengjie.modules.system.mapper.WxUserMapper;
import me.zhengjie.utils.FileUtil;
import lombok.RequiredArgsConstructor;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import me.zhengjie.modules.biz.service.EnrollSingleService;
import me.zhengjie.modules.biz.domain.vo.EnrollSingleQueryCriteria;
import me.zhengjie.modules.biz.mapper.EnrollSingleMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import me.zhengjie.utils.PageUtil;

import java.time.LocalDateTime;
import java.util.*;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;

import me.zhengjie.utils.PageResult;

import static me.zhengjie.modules.biz.constant.GlobalConstant.DEFAULT_LOGO;
import static me.zhengjie.modules.biz.domain.enums.ErrorCode.*;

/**
 * @description 服务实现
 * @author yiwei.he
 * @date 2024-03-11
 **/
@Service
@RequiredArgsConstructor
public class EnrollSingleServiceImpl extends ServiceImpl<EnrollSingleMapper, EnrollSingle> implements EnrollSingleService {

    private final EnrollSingleMapper enrollSingleMapper;

    private final WxUserMapper wxUserMapper;

    private final VipMapper vipMapper;

    @Value(value = "${url.default}")
    private String logoUrl;

    @Override
    public PageResult<EnrollSingle> queryAll(EnrollSingleQueryCriteria criteria, Page<Object> page){
        return PageUtil.toPage(enrollSingleMapper.findAll(criteria, page));
    }

    @Override
    public List<EnrollSingle> queryAll(EnrollSingleQueryCriteria criteria){
        return enrollSingleMapper.findAll(criteria);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(EnrollSingle resources) {
        save(resources);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(EnrollSingle resources) {
        EnrollSingle enrollSingle = getById(resources.getId());
        enrollSingle.copy(resources);
        saveOrUpdate(enrollSingle);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Long> ids) {
        removeBatchByIds(ids);
    }

    @Override
    public void download(List<EnrollSingle> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (EnrollSingle enrollSingle : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("办学性质", enrollSingle.getUquality());
            map.put("办学层次【本科/专科】", enrollSingle.getUtype());
            map.put("学校名称", enrollSingle.getUname());
            map.put("说明", enrollSingle.getRemark());
            map.put("普高（院校招生计划）", enrollSingle.getHplan());
            map.put("中职（院校招生计划）", enrollSingle.getVplan());
            map.put("合计（院校招生计划）", enrollSingle.getTotalPlan());
            map.put("总分【普高】", enrollSingle.getGrossScore());
            map.put("文化线【普高】", enrollSingle.getCultureLine());
            map.put("通用线【普高】", enrollSingle.getGeneralLine());
            map.put("上线分数【普高】", enrollSingle.getMinimumScore());
            map.put("计划数【普高】", enrollSingle.getPlanNumber());
            map.put("录取率【普高】", enrollSingle.getAcceptanceRate());
            map.put("成绩比例【普高】", enrollSingle.getGradeRate());
            map.put("预测分数【普高】", enrollSingle.getPredictedScore());
            map.put("分数差值【普高】", enrollSingle.getScoreDifference());
            map.put("文化线（中职）", enrollSingle.getVcultureLine());
            map.put("通用线（中职）", enrollSingle.getVgeneralLine());
            map.put("上线分数（中职）", enrollSingle.getVminimumScore());
            map.put("计划数（中职）", enrollSingle.getVplanNumber());
            map.put("录取率（中职）", enrollSingle.getVacceptanceRate());
            map.put("成绩比例（中职）", enrollSingle.getVgradeRate());
            map.put("预测分数（中职）", enrollSingle.getVpredictedScore());
            map.put("分数差值（中职）", enrollSingle.getVscoreDifference());
            map.put("删除【0：未删除，1已删除】", enrollSingle.getIsDelete());
            map.put("创建时间", enrollSingle.getCreateTime());
            map.put("修改时间", enrollSingle.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    /**
     * 高职单招：院校推荐
     * @param req
     * @return
     */
    @Override
    public UniversitiesRecommendResp recommendUniversities(UniversitiesRecommendReq req) throws BizException {
        UniversitiesRecommendResp resp = new UniversitiesRecommendResp();
        checkReq(req);
        // 查询用户信息和vip配置信息
        WxUser wxUser = wxUserMapper.selectOne(new QueryWrapper<WxUser>().eq("id", req.getUserId()));
        // 防止使用后管的token调用该方法
        if(null == wxUser){
            throw new BizException(USER_NOT_REGISTER.getCode(),USER_NOT_REGISTER.getMessage());
        }
        Vip vip = vipMapper.selectOne(new QueryWrapper<Vip>().eq("category", req.getCategory()));
        // 先查询是否属于免费期
        LocalDateTime currentDate = LocalDateTime.now();
        // 1.判断是否是智能建校触发，如果是，判断vip时间段以及有无推荐次数
        checkIsFirst(req,wxUser,vip,currentDate);

        Set<RecommendUniversitiesDTO> safeUniversities = new HashSet<>();
        Set<RecommendUniversitiesDTO> sureUniversities = new HashSet<>();
        Set<RecommendUniversitiesDTO> sprintUniversities = new HashSet<>();
        Set<RecommendUniversitiesDTO> governmentUniversities = new HashSet<>();
        Set<RecommendUniversitiesDTO> independentUniversities = new HashSet<>();
        Set<RecommendUniversitiesDTO> undergraduateList = null;

        // 2.通过高中、中职进行分类，然后再进行推荐【省控线等不同】
        if(1 == req.getSchoolType()){   // 高中
            undergraduateList = enrollSingleMapper.recommendByH(req);
        }else{  // 中职
            undergraduateList = enrollSingleMapper.recommendByM(req);
        }
        // 3.先分为公办和民办两类，然后再分稳、保、冲的状态
        for (RecommendUniversitiesDTO item : undergraduateList) {
            // 对院校进行分类
            recommendUniversities(req, item, governmentUniversities, independentUniversities, safeUniversities, sureUniversities, sprintUniversities);
        }
        // 4.封装获取到的数据
        setResultObject(resp, safeUniversities, sureUniversities, sprintUniversities, governmentUniversities, independentUniversities, wxUser);
        return resp;
    }

    private static void checkReq(UniversitiesRecommendReq req) throws BizException {
        // 检查入参
        if(req.getAddress() == null || req.getGender() == null || req.getSchoolType() == null || req.getCultureScore() == null
                || req.getGeneralScore() == null || req.getUserId() == null || req.getGrossScore() == null){
            throw new BizException(BODY_NOTNULL.getCode(),BODY_NOTNULL.getMessage());
        }
        // 单招分数段为0~500
        if(req.getGrossScore() > 500 || req.getGrossScore() < 0){
            throw new BizException(DZ_GROSS_SCORE_ERROR.getCode(),DZ_GROSS_SCORE_ERROR.getMessage());
        }
    }


    /**
     * 对院校进行分类
     * @param req
     * @param item
     * @param governmentUniversities
     * @param independentUniversities
     * @param safeUniversities
     * @param sureUniversities
     * @param sprintUniversities
     */
    private void recommendUniversities(UniversitiesRecommendReq req, RecommendUniversitiesDTO item, Set<RecommendUniversitiesDTO> governmentUniversities, Set<RecommendUniversitiesDTO> independentUniversities, Set<RecommendUniversitiesDTO> safeUniversities, Set<RecommendUniversitiesDTO> sureUniversities, Set<RecommendUniversitiesDTO> sprintUniversities) throws BizException {
        // 设置学生的分数
        item.setGrossScore(req.getGrossScore());
        // 如果失败率不为null,则进行减法运算
        if(item.getFailureRate() != null){
            item.setFailureRate(1 - item.getFailureRate());
        }
        // 查看学生的分数是否过线  文化线/通用线/总分省控线
        Double cultureLine = item.getCultureLine();
        Double generalLine = item.getGeneralLine();
        Double controlLine = item.getControlLine();
        if(req.getCultureScore() < cultureLine || req.getGeneralScore() < generalLine || req.getGrossScore() < controlLine){
            throw new BizException(SCORE_LOW_BASE_LINE.getCode(),SCORE_LOW_BASE_LINE.getMessage());
        }
        if(null != item.getUniversityQuality()){
            // 统一设置院校logo
            if(item .getLogo() == null){
                item.setLogo(logoUrl +  DEFAULT_LOGO);
            }
            // 公办院校
            if (0 == item.getUniversityQuality()) {
                governmentUniversities.add(item);
            }
            // 民办院校
            if (1 == item.getUniversityQuality()) {
                independentUniversities.add(item);
            }
            // 预测分数
            Double predictedScore = item.getPredictedScore();
            // 稳的条件要高于分数线50
            Double safe = predictedScore + 50;
            if (req.getGrossScore() >= safe) {
                item.setStatus(1);
                safeUniversities.add(item);
            } else if (req.getGrossScore() >= predictedScore) {
                item.setStatus(2);
                sureUniversities.add(item);
            } else {
                item.setStatus(3);
                sprintUniversities.add(item);
            }
        }
    }


    /**
     * 是否是智能建校触发
     * @param req
     * @param wxUser
     * @param vip
     * @param currentDate
     * @throws BizException
     */
    private void checkIsFirst(UniversitiesRecommendReq req, WxUser wxUser, Vip vip, LocalDateTime currentDate) throws BizException {
        // 判断是否是智能荐校
        if(req.getIsFirst() == 1){
            // 判断当前时间是否在给定时间段内  --- 单招
            if (vip.getStartTime() != null && vip.getEndTime() != null
                    && !currentDate.isBefore(vip.getStartTime()) && !currentDate.isAfter(vip.getEndTime())) {
                // 收费阶段，判断是否为vip,vip可以推荐两次，而普通用户只能推荐一次
                int maxRecommendNum = wxUser.getIsVip() == 1 ? 3 : 1;
                if (wxUser.getRecommendNum() >= maxRecommendNum) {
                    throw new BizException(RECOMMEND_NMU_MAX.getCode(),RECOMMEND_NMU_MAX.getMessage());
                }
                // 如果还有使用次数，先扣除使用次数，再进行评估，失败后回滚
                wxUser.setRecommendNum(wxUser.getRecommendNum() + 1);
                wxUserMapper.updateById(wxUser);
            }
        }
    }


    /**
     * 封装以及限制返回响应对象
     * @param resp
     * @param safeUniversities
     * @param sureUniversities
     * @param sprintUniversities
     * @param governmentUniversities
     * @param independentUniversities
     * @param wxUser
     */
    private void setResultObject(UniversitiesRecommendResp resp, Set<RecommendUniversitiesDTO> safeUniversities, Set<RecommendUniversitiesDTO> sureUniversities, Set<RecommendUniversitiesDTO> sprintUniversities, Set<RecommendUniversitiesDTO> governmentUniversities, Set<RecommendUniversitiesDTO> independentUniversities, WxUser wxUser) {
        resp.setSafeUniversitiesTotal(safeUniversities.size());
        resp.setSureUniversitiesTotal(sureUniversities.size());
        resp.setSprintUniversitiesTotal(sprintUniversities.size());
        resp.setGovernmentUniversitiesTotal(governmentUniversities.size());
        resp.setIndependentUniversitiesTotal(independentUniversities.size());
        // 5.限制集合数据展示
        if (wxUser.getIsVip() != 1) {
            limitUniversities(safeUniversities);
            limitUniversities(sureUniversities);
            limitUniversities(sprintUniversities);
            limitUniversities(governmentUniversities);
            limitUniversities(independentUniversities);
        }
        resp.setSafeUniversities(safeUniversities);
        resp.setSureUniversities(sureUniversities);
        resp.setSprintUniversities(sprintUniversities);
        resp.setGovernmentUniversities(governmentUniversities);
        resp.setIndependentUniversities(independentUniversities);
    }

    /**
     * 对非VIP用户进行限制，只能看到两所院校
     * @param universities
     */
    private void limitUniversities(Set<RecommendUniversitiesDTO> universities) {
        if (universities.size() > 2) {
            Iterator<RecommendUniversitiesDTO> iterator = universities.iterator();
            Set<RecommendUniversitiesDTO> limitedUniversities = new HashSet<>();
            limitedUniversities.add(iterator.next());
            limitedUniversities.add(iterator.next());
            // 清空原始集合
            universities.clear();
            // 将限制后的大学重新添加到原始集合中
            universities.addAll(limitedUniversities);
        }
    }


}